package com.qdd01.websocket;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qdd01.entity.Dto.CommentDto;
import com.qdd01.util.BaseContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
public class WebSocketHandler extends TextWebSocketHandler {

    private static final Logger logger = LoggerFactory.getLogger(WebSocketHandler.class);
    private static final Map<Integer, Map<Integer, WebSocketSession>> videoSessions = new ConcurrentHashMap<>();
    private static final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public void afterConnectionEstablished(WebSocketSession session) {
        try {
            Integer userId = getUserId(session);
            Integer videoId = getVideoId(session);
            
            if (userId != null) {
                if (videoId != null) {
                    Map<Integer, WebSocketSession> sessions = videoSessions.get(videoId);
                    if (sessions != null) {
                        WebSocketSession existingSession = sessions.get(userId);
                        if (existingSession != null && existingSession.isOpen()) {
                            existingSession.close();
                        }
                    }
                    
                    videoSessions.computeIfAbsent(videoId, k -> new ConcurrentHashMap<>())
                        .put(userId, session);
                    
                    logger.info("用户 {} 连接到视频 {} 的WebSocket, 当前该视频观看人数: {}", 
                        userId, videoId, videoSessions.get(videoId).size());
                    
                    logSessionsInfo();
                } else {
                    logger.info("用户 {} 建立基础WebSocket连接", userId);
                }
            } else {
                logger.error("无法获取用户ID，连接将被关闭");
                session.close(CloseStatus.PROTOCOL_ERROR);
            }
        } catch (Exception e) {
            logger.error("建立WebSocket连接时发生错误", e);
            try {
                session.close(CloseStatus.SERVER_ERROR);
            } catch (Exception ex) {
                logger.error("关闭WebSocket连接时发生错误", ex);
            }
        }
    }

    @Override
    public void handleTextMessage(WebSocketSession session, TextMessage message) {
        try {
            Integer userId = getUserId(session);
            if (userId != null) {
                logger.info("收到用户 {} 的消息: {}", userId, message.getPayload());
            }
        } catch (Exception e) {
            logger.error("处理消息时发生错误", e);
        }
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
        try {
            Integer userId = getUserId(session);
            Integer videoId = getVideoId(session);
            
            if (userId != null) {
                if (videoId != null) {
                    Map<Integer, WebSocketSession> sessions = videoSessions.get(videoId);
                    if (sessions != null) {
                        sessions.remove(userId);
                        if (sessions.isEmpty()) {
                            videoSessions.remove(videoId);
                        }
                        logger.info("用户 {} 断开视频 {} 的WebSocket连接, 当前该视频观看人数: {}", 
                            userId, videoId, sessions.size());
                    }
                } else {
                    logger.info("用户 {} 断开基础WebSocket连接", userId);
                }
            }
        } catch (Exception e) {
            logger.error("关闭WebSocket连接时发生错误", e);
        }
    }

    private Integer getUserId(WebSocketSession session) {
        try {
            Map<String, Object> attributes = session.getAttributes();
            if (attributes != null) {
                Object userId = attributes.get("userId");
                if (userId != null) {
                    return (Integer) userId;
                }
            }
            logger.warn("Session attributes 中未找到 userId");
            return BaseContext.getCurrentId();
        } catch (Exception e) {
            logger.error("获取用户ID时发生错误", e);
            return null;
        }
    }

    private Integer getVideoId(WebSocketSession session) {
        try {
            String path = session.getUri().getPath();
            String[] pathParts = path.split("/");
            if (pathParts.length > 0 && pathParts[pathParts.length - 1].equals("comment")) {
                return null;
            }
            String videoIdStr = pathParts[pathParts.length - 1];
            return Integer.parseInt(videoIdStr);
        } catch (Exception e) {
            logger.error("获取视频ID时发生错误: {}", e.getMessage());
            return null;
        }
    }

    // 广播评论到指定视频的所有连接
    public static void broadcastComment(Integer videoId, CommentDto comment) {
        logger.info("开始广播评论 - videoId: {}, commentId: {}, userId: {}", 
            videoId, comment.getId(), comment.getUserId());
        
        Map<Integer, WebSocketSession> sessions = videoSessions.get(videoId);
        if (sessions != null && !sessions.isEmpty()) {
            try {
                String message = objectMapper.writeValueAsString(comment);
                TextMessage textMessage = new TextMessage(message);
                
                logger.info("准备向视频 {} 的 {} 个用户广播评论", videoId, sessions.size());
                
                // 遍历所有会话并发送消息，包括发送者自己
                for (Map.Entry<Integer, WebSocketSession> entry : sessions.entrySet()) {
                    WebSocketSession session = entry.getValue();
                    Integer sessionUserId = entry.getKey();
                    
                    if (session != null && session.isOpen()) {
                        try {
                            session.sendMessage(textMessage);
                            logger.info("成功向用户 {} 发送评论消息", sessionUserId);
                        } catch (IOException e) {
                            logger.error("向用户 {} 发送评论失败: {}", sessionUserId, e.getMessage());
                            // 如果发送失败，不要立即移除会话，让重连机制处理
                        }
                    } else {
                        logger.warn("用户 {} 的会话已关闭或无效", sessionUserId);
                    }
                }
                
                logger.info("评论广播完成");
                
            } catch (JsonProcessingException e) {
                logger.error("评论序列化失败: {}", e.getMessage());
            }
        } else {
            logger.warn("视频 {} 没有活跃的WebSocket连接", videoId);
        }
    }

    // 添加会话信息日志方法
    private static void logSessionsInfo() {
        logger.info("当前WebSocket会话状态:");
        videoSessions.forEach((videoId, sessions) -> {
            logger.info("视频 {} 的会话数: {}", videoId, sessions.size());
            sessions.forEach((userId, session) -> {
                logger.info("- 用户 {}: isOpen={}", userId, session.isOpen());
            });
        });
    }

    // 获取当前在线连接数
    public static int getOnlineCount() {
        return videoSessions.values().stream()
            .mapToInt(Map::size)
            .sum();
    }

    // 检查指定用户是否在线
    public static boolean isUserOnline(Integer userId) {
        return videoSessions.values().stream()
            .anyMatch(sessions -> sessions.containsKey(userId));
    }

    // 向指定用户发送消息
    public static void sendMessage(Integer userId, String message) {
        videoSessions.values().stream()
            .filter(sessions -> sessions.containsKey(userId))
            .findFirst()
            .ifPresent(sessions -> {
                WebSocketSession session = sessions.get(userId);
                if (session != null && session.isOpen()) {
                    try {
                        session.sendMessage(new TextMessage(message));
                    } catch (IOException e) {
                        logger.error("向用户 {} 发送消息失败", userId, e);
                    }
                }
            });
    }

    // 广播消息给所有在线用户
    public static void broadcastMessage(String message) {
        videoSessions.values().stream()
            .flatMap(sessions -> sessions.values().stream())
            .forEach(session -> {
                if (session.isOpen()) {
                    try {
                        session.sendMessage(new TextMessage(message));
                    } catch (IOException e) {
                        logger.error("广播消息失败", e);
                    }
                }
            });
    }
}